home *** CD-ROM | disk | FTP | other *** search
-
- /* @(#)rev_ip.c 1.14 91/11/07
- *
- * Copyright (C) 1990, 1991 - Yves Gallot - all rights reserved.
- *
- * Permission is granted to copy this source, for redistribution
- * in source form only, provided the news headers in "substantially
- * unaltered format" are retained, the introductory messages are not
- * removed, and no monies are exchanged.
- *
- * Permission is also granted to copy this source, without the
- * news headers, for the purposes of making an executable copy by
- * means of compilation, provided that such copy will not be used
- * for the purposes of competition in any othello tournaments, without
- * prior permission from the authors.
- *
- * No responsibility is taken for any errors on inaccuracies inherent
- * either to the comments or the code of this program, but if reported
- * (see README file), then an attempt will be made to fix them.
- */
-
- #include <stdio.h>
- #include <signal.h>
- #include <setjmp.h>
- #include <sys/types.h>
- #include "reve.h"
-
- #define NOTE_DELTA 50
- #define INF 1000000000
-
- #define max(x,y) ((x)>(y)?x:y)
- #define min(x,y) ((x)<(y)?x:y)
-
- extern int debug ;
- extern int saveres ;
- extern time_t timeleft, time() ;
- extern int damier[NIVEAUMAX][64] ;
- extern int tacouleur, macouleur ;
- extern int mnb, profmax, max_depth ;
- extern long c1, c2, c3 ;
-
- extern int node_count ;
- static int tot_node_count ;
- static int top_note ; /* Best note found at top level of search */
-
- /* These global variables are only used in the play_reve routine. We place
- * them here as their values might otherwise be clobbered by some longjmp
- * implementations.
- */
- static int note, oldnote, oldnote2 ;
- static int oldprofmax, win_top, win_bot ;
-
- /* Reve structure. Play_Reve evaluates a board and returns a move and a note
- * for a given color.
- * It makes an interface between graphic variables and Reve heart variables.
- * It computes a timing function, depending on level used.
- * Then an Alpha-Beta pruning is called and stopped when no time left to Reve.
- * JePlonge and TuPlonges are typical F and G functions of an Alpha-Beta.
- * "Plonger dans un arbre" is the french translation of "to descend in a
- * tree", so I Descend and You Descend.
- */
-
- /* Modified by Robert Cohen, 10 Jan 1991
- * Changed search list reordering to make the principal variation
- * of the previous iteration the first path tried at each level
- * of the iterative deepening search.
- *
- * Added aspiration using failsoft alpha-beta to search.
- * Now tries search window of oldnote +- NOTE_DELTA
- */
-
- static int cpiinit[60] = { 0, 0, 7, 7,
- 2, 2, 5, 5, 2, 2, 3, 3,
- 4, 4, 5, 5, 1, 1, 3, 3,
- 4, 4, 6, 6, 1, 1, 2, 2,
- 5, 5, 6, 6, 0, 0, 0, 0,
- 2, 3, 4, 5, 2, 3, 4, 5,
- 7, 7, 7, 7, 1, 1, 6, 6,
- 0, 0, 1, 1, 6, 6, 7, 7
- } ;
-
- static int cpjinit[60] = { 0, 7, 0, 7,
- 2, 5, 2, 5, 3, 4, 2, 5,
- 2, 5, 3, 4, 3, 4, 1, 6,
- 1, 6, 3, 4, 2, 5, 1, 6,
- 1, 6, 2, 5, 2, 3, 4, 5,
- 0, 0, 0, 0, 7, 7, 7, 7,
- 2, 3, 4, 5, 1, 6, 1, 6,
- 1, 6, 0, 7, 0, 7, 1, 6
- } ;
-
- /* Total amount of time (in minutes) to allow, at this level of difficulty.
- * The time allocation function is not used at level 1.
- */
-
- static int timevals[MAXDIFF] = { 0, 1, 3, 5, 10, 15, 20, 30, 60 } ;
-
- static int cpi[60], cpj[60], cpk[60], cpf[60] ;
- static int cpi2[60], cpj2[60], cpk2[60] ;
- static int cpmaxi[NIVEAUMAX][NIVEAUMAX] ;
-
- static int locallevel = -1 ;
- static firsttime, timeused, allotime ;
-
- jmp_buf jumper ;
-
- static void catcher P(()) ;
-
- static long jeplonge P((int, long, long)) ;
- static long tuplonges P((int, long, long)) ;
- extern long evalue P((int)) ;
-
-
- static void
- catcher()
- {
- longjmp(jumper, 1) ;
- }
-
-
- int
- play_reve(board, color, level, rtnmv, rtnnote)
- int *board, color, level, *rtnmv ;
- long *rtnnote ;
- {
- register int *d0, *d1 ;
- register int k, cp ;
- register int count ;
- FILE *dp, *fp ;
- int pass ;
-
- if (debug == TRUE)
- if ((dp = fopen("reve.debug", "a")) == NULL)
- debug = FALSE ;
-
- for (k = 0; k < 60; k++)
- {
- cpi[k] = cpiinit[k] ;
- cpj[k] = cpjinit[k] ;
- cpk[k] = 8 * cpi[k] + cpj[k] ;
- }
-
- d0 = damier[0] ;
- d1 = damier[1] ;
-
- for (k = 0; k < 64; k++)
- {
- if (board[k] == BLACK) d0[k] = BLACK ;
- else if (board[k] == WHITE) d0[k] = WHITE ;
- else d0[k] = FREE ;
- }
-
- if (color == WHITE)
- {
- macouleur = WHITE ;
- tacouleur = BLACK ;
- }
- else
- {
- macouleur = BLACK ;
- tacouleur = WHITE ;
- }
-
- if (jepeuxjouer(0) == FALSE)
- {
- *rtnmv = -1 ;
- return ;
- }
-
- mnb = 1 ;
- for (k = 0; k < 64; k++)
- if ((k != 27) && (k != 28) && (k != 35) && (k != 36))
- if ((d0[k] == WHITE) || (d0[k] == BLACK))
- {
- mnb++ ;
- cp = 0 ;
- while (cpk[cp] != k) cp++ ;
- for ( ; cp < 59; cp++)
- {
- cpi[cp] = cpi[cp + 1] ;
- cpj[cp] = cpj[cp + 1] ;
- cpk[cp] = cpk[cp + 1] ;
- }
- }
-
- if ((locallevel != level) || (mnb == 1) || (mnb == 2))
- {
- timeleft = timevals[level-1] * 60 ;
- locallevel = level ;
- }
-
- k = 0 ;
- for (cp = 0; cp <= 60 - mnb; cp++)
- if (d0[cpk[cp]] == JPJ) k++ ;
-
- count = note = 0 ;
- timeused = 1 ;
- profmax = max_depth - 1 ;
-
- if (((k == 1) && (mnb < 52)) || (mnb == 1))
- {
- for (cp = 0; d0[cpk[cp]] != JPJ; cp++) continue ;
- cpi[0] = cpi[cp] ;
- cpj[0] = cpj[cp] ;
- cpk[0] = cpk[cp] ;
- }
- else if (mnb == 2)
- {
- if (d0[2 * 8 + 3] == BLACK)
- {
- cpi[0] = 4 ;
- cpj[0] = 2 ;
- }
- else if (d0[3 * 8 + 2] == BLACK)
- {
- cpi[0] = 2 ;
- cpj[0] = 4 ;
- }
- else if (d0[4 * 8 + 5] == BLACK)
- {
- cpi[0] = 5 ;
- cpj[0] = 3 ;
- }
- else if (d0[5 * 8 + 4] == BLACK)
- {
- cpi[0] = 3 ;
- cpj[0] = 5 ;
- }
- cpk[0] = cpi[0] * 8 + cpj[0] ;
- }
- else if (mnb == 3)
- {
- if (d0[4 * 8 + 2] == WHITE)
- {
- cpi[0] = 5 ;
- cpj[0] = 3 ;
- }
- else if (d0[2 * 8 + 2] == WHITE)
- {
- cpi[0] = 3 ;
- cpj[0] = 2 ;
- }
- else if (d0[2 * 8 + 4] == WHITE)
- {
- cpi[0] = 3 ;
- cpj[0] = 5 ;
- }
- cpk[0] = cpi[0] * 8 + cpj[0] ;
- }
- else
- {
- allotime = timeleft * 4 / (61 - mnb) ;
- firsttime = time((time_t *) NULL) ;
- tot_node_count = 0 ;
- pass = 0 ;
-
- win_top = win_bot = oldnote = oldprofmax = 0 ;
-
- SIGNAL(SIGALRM, catcher) ;
-
- if (setjmp(jumper) != 0)
- {
- if (debug)
- {
- FPRINTF(dp, "%d nodes visited when interrupted", node_count) ;
- FPRINTF(dp, " at ply %d, note = %d\n", profmax, top_note) ;
- }
- tot_node_count += node_count ;
-
- if (top_note <= win_bot || top_note >= win_top)
- {
-
- /* Didn't find move at this level so restore principal variation from
- * last level.
- */
- if (debug)
- FPRINTF(dp, "no valid move found in window %d - %d\n",
- win_bot, win_top) ;
- note = oldnote ;
- profmax = oldprofmax ;
- for (k = 0; k < profmax; k++)
- {
- cpi[k] = cpi2[k] ;
- cpj[k] = cpj2[k] ;
- cpk[k] = cpk2[k] ;
- }
- }
- else
- {
-
- /* Copy from principal variation into cpi... */
-
- for (k = 0; k < profmax; k++)
- {
- cpi2[k] = cpi[cpmaxi[0][k]] ;
- cpj2[k] = cpj[cpmaxi[0][k]] ;
- cpk2[k] = cpk[cpmaxi[0][k]] ;
- }
- for (k = 0; k < profmax; k++)
- {
- cpi[k] = cpi2[k] ;
- cpj[k] = cpj2[k] ;
- cpk[k] = cpk2[k] ;
- }
- profmax = -profmax ;
- note = top_note ;
- }
- goto trap ;
- }
-
- do
- {
- oldnote2 = oldnote ;
- oldnote = note ;
- oldprofmax = profmax ;
- top_note = -INF ;
- node_count = 0 ;
-
- if ((int) (allotime - timeused) > 2)
- ALARM((unsigned) (allotime - timeused)) ;
-
- profmax++ ;
- pass++ ;
-
- c1 = 312 + 6 * (mnb + profmax - 1) ;
- if (mnb + profmax - 1 < 25)
- c2 = 50 + 2 * (mnb + profmax - 1) ;
- else
- c2 = 75 + mnb + profmax - 1 ;
- c3 = 99 ;
-
- if (profmax > 53 - mnb)
- {
- profmax = 61 - mnb ;
- allotime = timeleft * 2 / 3 ;
- if ((int) (allotime - timeused) > 2)
- ALARM((unsigned) (allotime - timeused)) ;
- }
-
- if (pass > 2 && profmax < 61 - mnb)
- {
-
- /* Use aspiration search */
-
- if (abs(oldnote2) < NOTE_DELTA * 2)
- {
- win_bot = oldnote2 - NOTE_DELTA ;
- win_top = oldnote2 + NOTE_DELTA ;
- }
- else
- {
- win_bot = min(oldnote2 * 1.5, oldnote2 / 2) ;
- win_top = max(oldnote2 * 1.5, oldnote2 / 2) ;
- }
- note = jeplonge(0, win_bot, win_top) ;
- if (note >= win_top)
- {
- if (debug)
- {
- FPRINTF(dp, "failing high, note = %d, ", note) ;
- FPRINTF(dp, "win top = %d, wasted nodes visited = %d\n",
- win_top, node_count) ;
- }
- win_top = INF ;
- win_bot = note ;
- top_note = -INF ;
- note = jeplonge(0, win_bot, win_top) ;
- }
- else if (note <= win_bot)
- {
- if (debug)
- {
- FPRINTF(dp, "failing low, note = %d, ", note) ;
- FPRINTF(dp, "win bot = %d, wasted nodes visited = %d\n",
- win_bot, node_count) ;
- }
- win_bot = -INF ;
- win_top = note ;
- top_note = -INF ;
- note = jeplonge(0, win_bot, win_top) ;
- }
- }
- else
- {
- win_bot = -INF ;
- win_top = INF ;
- note = jeplonge(0, win_bot, win_top) ;
- }
-
- ALARM(0) ;
- if (cpmaxi[0][0] == 0) count += 2 ;
- else count = 1 ;
-
- for (cp = 0; cp <= 60 - mnb; cp++) cpf[cp] = TRUE ;
- for (k = 0; k < profmax; k++)
- {
- cpi2[k] = cpi[cpmaxi[0][k]] ;
- cpj2[k] = cpj[cpmaxi[0][k]] ;
- cpk2[k] = cpk[cpmaxi[0][k]] ;
- cpf[cpmaxi[0][k]] = FALSE ;
- }
- k = profmax ;
- for (cp = 0; cp <= 60 - mnb; cp++)
- if (cpf[cp] == TRUE)
- {
- cpi2[k] = cpi[cp] ;
- cpj2[k] = cpj[cp] ;
- cpk2[k] = cpk[cp] ;
- k++ ;
- }
- for (cp = 0; cp <= 60 - mnb; cp++)
- {
- cpi[cp] = cpi2[cp] ;
- cpj[cp] = cpj2[cp] ;
- cpk[cp] = cpk2[cp] ;
- }
-
- timeused = time((time_t *) NULL) - firsttime ;
- if (debug)
- {
- FPRINTF(dp, "%d nodes visited at ply %d,", node_count, profmax) ;
- FPRINTF(dp, " window %0.4g - %0.4g,",
- (float) win_bot, (float) win_top) ;
- FPRINTF(dp, " note = %d, best move = <%c-%c>\n",
- note, 'A' + cpj[0], '1' + cpi[0]) ;
- }
- tot_node_count += node_count ;
- if ((mnb == 4) && (profmax > 2)) break ;
- }
- while ((timeused * count < allotime * 4 / 5) && (profmax != 61 - mnb)) ;
-
- trap:
-
- timeused = time((time_t *) NULL) - firsttime ;
- if (timeused == 0) timeused = 1 ;
-
- if (debug)
- {
- FPRINTF(dp, "total nodes visited was %d, time used was %d secs,",
- tot_node_count, timeused) ;
- FPRINTF(dp, " %d nodes/sec\n", tot_node_count / timeused) ;
- FPRINTF(dp, "alloc'ed time was %d, time left = %d\n",
- allotime, timeleft - timeused);
- FPRINTF(dp, "best move sequence: ") ;
- for (k = 0; k < abs(profmax); k++)
- FPRINTF(dp, "<%c-%c>, ", 'A' + cpj[k], '1' + cpi[k]) ;
- FPRINTF(dp, "\n") ;
- }
- }
-
- if (*rtnmv == TRUE) timeleft -= timeused ;
- if ((int) timeleft < 0) timeleft = 0 ;
-
- if (saveres)
- {
- if ((mnb == 1) || (mnb == 2))
- {
- fp = fopen("reve.res", "w") ;
- FPRINTF(fp, "\n") ;
- FCLOSE(fp) ;
- }
- fp = fopen("reve.res", "a") ;
- FPRINTF(fp, "%2d, <%c-%c>, ", mnb, 'A' + cpj[0], '1' + cpi[0]) ;
- FPRINTF(fp, "nt : %5d, pmax : %3d, tmleft : %d, level : %d, ",
- note, profmax, timeleft, level) ;
- FPRINTF(fp, "exp : <%c-%c>\n", 'A' + cpj[1], '1' + cpi[1]) ;
- FCLOSE(fp) ;
- }
-
- *rtnmv = cpk[0] ;
- *rtnnote = note ;
- if (debug) FCLOSE(dp) ;
- }
-
-
- /* If interrupted, global variables top_note contains the best note
- * found, cpmaxi[0] contains the principal variation.
- */
-
- static long
- jeplonge(niv, alpha, beta)
- int niv ;
- long alpha, beta ;
- {
- register int *d0, *d1 ;
- register int k, cp ;
- register long lnote, note ;
- int atime;
-
- d0 = damier[niv] ;
- d1 = damier[niv + 1] ;
-
- note = -INF ;
-
- for (cp = 0; cp <= 60 - mnb; cp++)
- {
- if (d0[cpk[cp]] == JPJ)
- {
- #ifdef hp9000s300
- for (k = 0; k < 64; k++) damier[niv + 1][k] = damier[niv][k] ;
- #else
- for (k = 0; k < 64; k++) d1[k] = d0[k] ;
- #endif
- jejoueen(cpi[cp], cpj[cp], niv + 1) ;
- if (niv == profmax - 1) lnote = evalue(niv + 1) ;
- else if (tupeuxjouer(niv + 1) == TRUE)
- lnote = tuplonges(niv + 1, max(note,alpha), beta) ;
- else if (jepeuxjouer(niv + 1) == TRUE)
- lnote = jeplonge(niv + 1, max(note,alpha), beta) ;
- else
- lnote = evalue(niv + 1) ;
- if (lnote > note)
- {
- if (niv == 0)
- {
- atime = alarm(0) ;
- note = lnote ;
- for (k = niv + 1; k < profmax; k++)
- cpmaxi[niv][k] = cpmaxi[niv+1][k] ;
- cpmaxi[niv][niv] = cp ;
- top_note = note ;
- show_best(cpk[cp],note) ;
- ALARM(atime) ;
- }
- else
- {
- note = lnote ;
- for (k = niv + 1; k < profmax; k++)
- cpmaxi[niv][k] = cpmaxi[niv+1][k] ;
- cpmaxi[niv][niv] = cp ;
- }
- }
- if (note >= beta) return note ;
- }
- }
-
- return note ;
- }
-
-
- static long
- tuplonges(niv, alpha, beta)
- int niv ;
- long alpha, beta ;
- {
- register int *d0, *d1 ;
- register int k, cp ;
- register long lnote, note ;
-
- d0 = damier[niv] ;
- d1 = damier[niv + 1] ;
-
- note = INF ;
-
- for (cp = 0; cp <= 60 - mnb; cp++)
- {
- if (d0[cpk[cp]] == TPJ)
- {
- #ifdef hp9000s300
- for (k = 0; k < 64; k++) damier[niv + 1][k] = damier[niv][k] ;
- #else
- for (k = 0; k < 64; k++) d1[k] = d0[k] ;
- #endif
- tujouesen(cpi[cp], cpj[cp], niv + 1) ;
- if (niv == profmax - 1) lnote = evalue(niv + 1) ;
- else if (jepeuxjouer(niv + 1) == TRUE)
- lnote = jeplonge(niv + 1, alpha, min(note,beta)) ;
- else if (tupeuxjouer(niv + 1) == TRUE)
- lnote = tuplonges(niv + 1, alpha, min(note,beta)) ;
- else
- lnote = evalue(niv + 1) ;
- if (lnote < note)
- {
- note = lnote ;
- for (k = niv + 1; k < profmax; k++)
- cpmaxi[niv][k] = cpmaxi[niv+1][k] ;
- cpmaxi[niv][niv] = cp;
- }
- if (note <= alpha) return note ;
- }
- }
-
- return note ;
- }
-